
import dpkt  
from dpkt.pcap import Reader  
import numpy as np  
from scipy.stats import skew, kurtosis  
import sub_sq as sbq
from collections import Counter
import math
import copy


def cal_tint_entropy(data):
    # calculate_discrete_entropy
    """  
    计算离散熵。  

    参数:  
    data -- 输入的浮点型数据数组  
    num_bins -- 要创建的桶的数量  

    返回:  
    entropy -- 离散熵的值  
    """  
    # discretized_data, num_bins = discretize_data(data)

    if len(data) == 0:
        return 0.0
    unique_values = np.unique(data)  
    if len(unique_values) == 1:  
        # 如果所有值都相同，则无法计算离散熵，返回None或者其他适当的值  
        return 0.0  

    min_val = np.min(data)  
    max_val = np.max(data)  
    if min_val == max_val:  
        # 如果最小值等于最大值（即使不是所有值都相同），仍然无法划分桶  
        return 0.0
    if len(data)> 9:
        num_bins = 5
    elif len(data)>2 and len(data)<10:
        num_bins = 2
    else:
        num_bins = 1

    bin_width = (max_val - min_val) / num_bins
    discretized_data = np.digitize(data, np.arange(min_val, max_val + bin_width, bin_width)) - 1 


    # if discretized_data is None:  
    #     # 所有值都相同，无法计算离散熵  
    #     return 0.0  # 或者抛出异常，或者返回其他适当的值  

    freq_counts = np.bincount(discretized_data) / len(discretized_data)  
    freq_counts = freq_counts[freq_counts > 0]  # 移除频率为0的桶  
    entropy = -np.sum(freq_counts * np.log2(freq_counts))  
    return entropy

def cal_histogram_entropy(data): 
    # calculate_histogram_entropy

    if len(data) == 0:
        return 0.0
    unique_values = np.unique(data)  
    if len(unique_values) == 1:  
        # 如果所有值都相同，则无法计算离散熵，返回None或者其他适当的值  
        return 0.0

    if len(data)> 9:
        num_bins = 5
    elif len(data)>2 and len(data)<10:
        num_bins = 2
    else:
        num_bins = 1
    # 计算直方图  
    counts, bin_edges = np.histogram(data, bins=num_bins, density=True)  

    # 归一化直方图计数为概率分布  
    probabilities = counts / np.sum(counts)  

    # 计算熵  
    entropy = -np.sum(probabilities * np.log2(probabilities + np.finfo(float).eps))  

    return entropy

def cal_cv(data):  
    """  
    计算给定数据集的变异系数  
    :param data: 数据集，可以是列表、NumPy数组等  
    :return: 变异系数  
    """
    if len(data) == 0:
        return 0
    mean = np.mean(data)  
    std_dev = np.std(data)  

    # 避免除以零的情况  
    if mean == 0:  
        return 0  

    cv = std_dev / mean
    return cv

def differences_adjacent(lst):  
    return [b - a for a, b in zip(lst[:-1], lst[1:])] 
    
def negative_to_positive(lst):
# 创建一个新的列表来存储修改后的元素  
    positive_lst = []  
    # 遍历原始列表中的每个元素  
    for num in lst:  
        # 如果元素是负数，则取绝对值（转换为正数）  
        if num < 0:  
            positive_lst.append(abs(num))  
        elif num == 0.0:
            continue
        else:  
            positive_lst.append(num)  
    # 返回新的列表  
    return positive_lst 


def negative_to_positive2(lst):
# 创建一个新的列表来存储修改后的元素  
    positive_lst = []  
    # 遍历原始列表中的每个元素  
    for num in lst:  
        # 如果元素是负数，则取绝对值（转换为正数）  
        if num < 0:  
            if abs(num) in lst:
                continue
            else:
                positive_lst.append(abs(num))  
        # elif num == 0.0:
        #     continue
        else:  
            positive_lst.append(num)  
    # 返回新的列表  
    return positive_lst 

# print(negative_to_positive2([-1,-1,-4,0,1]))


def find_mode_or_average(sequence):  
    # 使用Counter统计每个元素出现的次数  
    counts = Counter(sequence)  
    min_val = round(np.min(sequence, axis=0), 6)

    # 找出出现次数最多的次数  
    max_count = max(counts.values())  

    # 找出所有出现次数等于max_count的元素  
    modes = [num for num, count in counts.items() if count == max_count]  

    # 如果没有众数（例如空序列），返回None或适当值  
    if not modes:  
        return min_val  # 或者你可以返回一个默认值，比如0  

    # 如果有多个众数，计算它们的算数平均数  
    if len(modes) > 1:  
        return sum(modes) / len(modes)  

    # 否则，返回唯一的众数  
    return modes[0]  


def calc_slope(lis, x, y):
    m = y - x
    p_x = round(np.percentile(lis, x), 6)
    p_y = round(np.percentile(lis, y), 6)
    if int(len(lis)*m/100) != 0:
        k = round(((p_y-p_x) / int(len(lis)*m/100)), 6)
    else:
        k = 0.0
    return k

def generate_index_pairs(start_values, end_values):  
    pairs = []  
    for start in start_values:  
        for end in end_values:  
            if (start + end) < max(start_values):  # 确保 start < end  
                pairs.append((start, start + end))  
    return pairs

def calc_for_Zsc(l, AK47_A):
                        
    if l == []:
        # return [None] * (5 + 19 + 2 + 1 + 1)
        return [None] * AK47_A
    
    slopes = {}  

    K1071 = [(0,25),(0,50),(0,75),(0,95),(25,50),(25,75),(45,95),(50,75),(25,95),(75,95),(50,95),(0,100)] #length: 31
    
    
    for start, end in K1071:   
        key = f'k_{start}_{end}'  
        slopes[key] = calc_slope(l, start, end)  
    k_val_list = [] 
    for key, value in slopes.items():  
        k_val_list.append(value)
    
    range_ori = np.max(l, axis=0) - np.min(l, axis=0)
    normalsize_l = sbq.zscore_nor(l)

    range_nor = np.max(normalsize_l, axis=0) - np.min(normalsize_l, axis=0)

    median_val = round(np.median(normalsize_l, axis=0), 6)
    
    skewness_val = round(skew(normalsize_l, axis=0), 6)
    kurtosis_val = round(kurtosis(normalsize_l, axis=0), 6)
    p_25 = round(np.percentile(normalsize_l, 25), 6)
    p_75 = round(np.percentile(normalsize_l, 75), 6)
    p_95 = round(np.percentile(normalsize_l, 95), 6)
    iqr = p_75 - p_25

    # tentr: tint_entropys
    # hentr: histogram_entropys
    tentr = round(float(cal_tint_entropy(normalsize_l)), 6)
    hentr = round(float(cal_histogram_entropy(normalsize_l)), 6)

    if np.min(normalsize_l, axis=0) != 0.0:
        r_3 = np.min(normalsize_l, axis=0)
        min_tentr = round(float((cal_tint_entropy(normalsize_l)) / r_3), 6)
        min_hentr = round(float((cal_histogram_entropy(normalsize_l)) / r_3), 6)
    else:
        min_tentr = tentr
        min_hentr = hentr

    if np.max(normalsize_l, axis=0) != 0.0:
        r_2 = np.max(normalsize_l, axis=0)
        max_tentr = round(float((cal_tint_entropy(normalsize_l)) / r_2), 6)
        max_hentr = round(float((cal_histogram_entropy(normalsize_l)) / r_2), 6)
    else:
        max_tentr = tentr
        max_hentr = hentr

    if (np.max(normalsize_l, axis=0) - np.min(normalsize_l, axis=0)) != 0.0:
        r_1 = (np.max(normalsize_l, axis=0) - np.min(normalsize_l, axis=0))
        range_tentr = round(float((cal_tint_entropy(normalsize_l)) / r_1), 6)
        range_hentr = round(float((cal_histogram_entropy(normalsize_l)) / r_1), 6)
    else:
        range_tentr = tentr
        range_hentr = hentr
    
    if median_val != 0.0:
        p50_tentr = round(float((cal_tint_entropy(normalsize_l)) / median_val), 6)
        p50_hentr = round(float((cal_histogram_entropy(normalsize_l)) /median_val), 6)
    else:
        p50_tentr = tentr
        p50_hentr = hentr

    percentile_list = []
    percentile_list.append(round(np.percentile(normalsize_l, 5), 6))
    percentile_list.append(round(np.percentile(normalsize_l, 25), 6))
    percentile_list.append(round(np.percentile(normalsize_l, 35), 6))
    percentile_list.append(round(np.percentile(normalsize_l, 90), 6))
    percentile_list.append(round(np.percentile(normalsize_l, 95), 6))


    final_list_sub01 = [range_ori, range_nor]
    #''' 2 '''
    final_list_sub02 = k_val_list
    #''' length: 31 + 4 '''
    final_list_sub03 = [median_val, skewness_val, kurtosis_val, iqr] + percentile_list 
    #''' 4+5 '''
    # final_list_sub03 = [median_val, skewness_val, kurtosis_val]
    final_list_sub04 = [tentr, hentr, min_tentr, min_hentr, max_tentr, max_hentr, range_tentr, range_hentr, p50_tentr, p50_hentr]#, p25_tentr, p25_hentr, p50_tentr, p50_hentr, p75_tentr, p75_hentr, p95_tentr, p95_hentr]
    #''' 10 '''

    # leng = 2 + 12 + 4 + 5 + 10
    final_list = final_list_sub01 + final_list_sub02 + final_list_sub03 + final_list_sub04
    return final_list